using Lzfy_His_Service.Models;
using Lzfy_His_Service.Repositories;

namespace Lzfy_His_Service.Services
{
    public class RefundTaskMasterService : IRefundTaskMasterService
    {
        private readonly IRefundTaskMasterRepository _repository;
        private readonly IRefundTaskDetailRepository _detailRepository;
        private readonly ILogger<RefundTaskMasterService> _logger;

        public RefundTaskMasterService(
            IRefundTaskMasterRepository repository,
            IRefundTaskDetailRepository detailRepository,
            ILogger<RefundTaskMasterService> logger)
        {
            _repository = repository;
            _detailRepository = detailRepository;
            _logger = logger;
        }

        public async Task<RefundTaskMasterResponse?> GetByIdAsync(long id)
        {
            try
            {
                var master = await _repository.GetByIdAsync(id);
                if (master == null) return null;

                var details = await _detailRepository.GetByMasterIdAsync(id);
                
                return new RefundTaskMasterResponse
                {
                    Id = master.Id,
                    InputDate = master.InputDate,
                    Username = master.Username,
                    Fullname = master.Fullname,
                    AccountCount = master.AccountCount,
                    AccountSumBalance = master.AccountSumBalance,
                    Details = details.Select(d => new RefundTaskDetailResponse
                    {
                        Id = d.Id,
                        InputDate = d.InputDate,
                        MasterId = d.MasterId,
                        PatientId = d.PatientId,
                        AccountId = d.AccountId,
                        AccountIndex = d.AccountIndex,
                        Balance = d.Balance,
                        ContactCount = d.ContactCount,
                        ContactTime1 = d.ContactTime1?.ToLocalTime(),
                        ContactTime2 = d.ContactTime2?.ToLocalTime(),
                        ContactTime3 = d.ContactTime3?.ToLocalTime(),
                        ContactTime4 = d.ContactTime4?.ToLocalTime(),
                        ContactTime5 = d.ContactTime5?.ToLocalTime(),
                        PhoneNumber = d.PhoneNumber,
                        PatName = d.PatName,
                        IdNumber = d.IdNumber,
                        Sex = d.Sex,
                        NextOfKin = d.NextOfKin,
                        NextOfKinPhone = d.NextOfKinPhone,
                        GuardianName = d.GuardianName,
                        GuardianIdcode = d.GuardianIdcode
                    }).ToList()
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting refund task master by id: {Id}", id);
                throw;
            }
        }

        public async Task<(IEnumerable<RefundTaskMasterResponse> Data, int TotalCount)> GetAllPagedAsync(int pageIndex = 1, int pageSize = 100)
        {
            try
            {
                var (masters, totalCount) = await _repository.GetAllPagedAsync(pageIndex, pageSize);
                var responses = new List<RefundTaskMasterResponse>();

                // 批量获取明细数据，避免N+1查询问题
                var masterIds = masters.Select(m => m.Id).ToList();
                var allDetails = await _detailRepository.GetByMasterIdsAsync(masterIds);
                
                var detailsLookup = allDetails.GroupBy(d => d.MasterId)
                    .Where(g => g.Key.HasValue)
                    .ToDictionary(g => g.Key!.Value, g => g.ToList());

                foreach (var master in masters)
                {
                    var details = detailsLookup.ContainsKey(master.Id) ? detailsLookup[master.Id] : new List<RefundTaskDetail>();
                    responses.Add(new RefundTaskMasterResponse
                    {
                        Id = master.Id,
                        InputDate = master.InputDate,
                        Username = master.Username,
                        Fullname = master.Fullname,
                        AccountCount = master.AccountCount,
                        AccountSumBalance = master.AccountSumBalance,
                        Details = details.Select(d => new RefundTaskDetailResponse
                        {
                            Id = d.Id,
                            InputDate = d.InputDate,
                            MasterId = d.MasterId,
                            PatientId = d.PatientId,
                            AccountId = d.AccountId,
                            AccountIndex = d.AccountIndex,
                            Balance = d.Balance,
                            ContactCount = d.ContactCount,
                            ContactTime1 = d.ContactTime1?.ToLocalTime(),
                            ContactTime2 = d.ContactTime2?.ToLocalTime(),
                            ContactTime3 = d.ContactTime3?.ToLocalTime(),
                            ContactTime4 = d.ContactTime4?.ToLocalTime(),
                            ContactTime5 = d.ContactTime5?.ToLocalTime(),
                            PhoneNumber = d.PhoneNumber,
                            PatName = d.PatName,
                            IdNumber = d.IdNumber,
                            Sex = d.Sex,
                            NextOfKin = d.NextOfKin,
                            NextOfKinPhone = d.NextOfKinPhone,
                            GuardianName = d.GuardianName,
                            GuardianIdcode = d.GuardianIdcode
                        }).ToList()
                    });
                }

                return (responses, totalCount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting all refund task masters paged");
                throw;
            }
        }

        public async Task<(IEnumerable<RefundTaskMasterResponse> data, int totalCount)> GetWithFilterAsync(RefundTaskMasterQueryRequest request)
        {
            try
            {
                var (data, totalCount) = await _repository.GetWithFilterAsync(
                    request.StartDate,
                    request.EndDate,
                    request.Username,
                    request.Fullname,
                    request.PageIndex,
                    request.PageSize);

                var responses = new List<RefundTaskMasterResponse>();

                foreach (var master in data)
                {
                    var details = await _detailRepository.GetByMasterIdAsync(master.Id);
                    responses.Add(new RefundTaskMasterResponse
                    {
                        Id = master.Id,
                        InputDate = master.InputDate,
                        Username = master.Username,
                        Fullname = master.Fullname,
                        AccountCount = master.AccountCount,
                        AccountSumBalance = master.AccountSumBalance,
                        Details = details.Select(d => new RefundTaskDetailResponse
                        {
                            Id = d.Id,
                            InputDate = d.InputDate,
                            MasterId = d.MasterId,
                            PatientId = d.PatientId,
                            AccountId = d.AccountId,
                            AccountIndex = d.AccountIndex,
                            Balance = d.Balance,
                            ContactCount = d.ContactCount,
                            ContactTime1 = d.ContactTime1?.ToLocalTime(),
                            ContactTime2 = d.ContactTime2?.ToLocalTime(),
                            ContactTime3 = d.ContactTime3?.ToLocalTime(),
                            ContactTime4 = d.ContactTime4?.ToLocalTime(),
                            ContactTime5 = d.ContactTime5?.ToLocalTime(),
                            PhoneNumber = d.PhoneNumber,
                            PatName = d.PatName,
                            IdNumber = d.IdNumber,
                            Sex = d.Sex,
                            NextOfKin = d.NextOfKin,
                            NextOfKinPhone = d.NextOfKinPhone,
                            GuardianName = d.GuardianName,
                            GuardianIdcode = d.GuardianIdcode
                        }).ToList()
                    });
                }

                return (responses, totalCount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting refund task masters with filter");
                throw;
            }
        }

        public async Task<IEnumerable<RefundTaskMasterResponse>> GetByUsernameAsync(string username)
        {
            try
            {
                var masters = await _repository.GetByUsernameAsync(username);
                var responses = new List<RefundTaskMasterResponse>();

                foreach (var master in masters)
                {
                    responses.Add(new RefundTaskMasterResponse
                    {
                        Id = master.Id,
                        InputDate = master.InputDate,
                        Username = master.Username,
                        Fullname = master.Fullname,
                        AccountCount = master.AccountCount,
                        AccountSumBalance = master.AccountSumBalance,
                        Details = new List<RefundTaskDetailResponse>() // 不返回明细数据，只返回空列表
                    });
                }

                return responses;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting refund task masters by username: {Username}", username);
                throw;
            }
        }

        public async Task<IEnumerable<RefundTaskMasterResponse>> GetAllAsync()
        {
            try
            {
                var masters = await _repository.GetAllAsync();
                var responses = new List<RefundTaskMasterResponse>();

                foreach (var master in masters)
                {
                    var details = await _detailRepository.GetByMasterIdAsync(master.Id);
                    responses.Add(new RefundTaskMasterResponse
                    {
                        Id = master.Id,
                        InputDate = master.InputDate,
                        Username = master.Username,
                        Fullname = master.Fullname,
                        AccountCount = master.AccountCount,
                        AccountSumBalance = master.AccountSumBalance,
                        Details = details.Select(d => new RefundTaskDetailResponse
                        {
                            Id = d.Id,
                            InputDate = d.InputDate,
                            MasterId = d.MasterId,
                            PatientId = d.PatientId,
                            AccountId = d.AccountId,
                            AccountIndex = d.AccountIndex,
                            Balance = d.Balance,
                            ContactCount = d.ContactCount,
                            ContactTime1 = d.ContactTime1?.ToLocalTime(),
                            ContactTime2 = d.ContactTime2?.ToLocalTime(),
                            ContactTime3 = d.ContactTime3?.ToLocalTime(),
                            ContactTime4 = d.ContactTime4?.ToLocalTime(),
                            ContactTime5 = d.ContactTime5?.ToLocalTime(),
                            PhoneNumber = d.PhoneNumber,
                            PatName = d.PatName,
                            IdNumber = d.IdNumber,
                            Sex = d.Sex,
                            NextOfKin = d.NextOfKin,
                            NextOfKinPhone = d.NextOfKinPhone,
                            GuardianName = d.GuardianName,
                            GuardianIdcode = d.GuardianIdcode
                        }).ToList()
                    });
                }

                return responses;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting all refund task masters");
                throw;
            }
        }

        public async Task<long> CreateAsync(RefundTaskMasterCreateRequest request)
        {
            try
            {
                var master = new RefundTaskMaster
                {
                    Username = request.Username,
                    Fullname = request.Fullname,
                    AccountCount = request.AccountCount,
                    AccountSumBalance = request.AccountSumBalance
                };

                return await _repository.CreateAsync(master);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error creating refund task master");
                throw;
            }
        }

        public async Task<bool> UpdateAsync(long id, RefundTaskMasterUpdateRequest request)
        {
            try
            {
                var existing = await _repository.GetByIdAsync(id);
                if (existing == null) return false;

                existing.Username = request.Username;
                existing.Fullname = request.Fullname;
                existing.AccountCount = request.AccountCount;
                existing.AccountSumBalance = request.AccountSumBalance;

                return await _repository.UpdateAsync(existing);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating refund task master: {Id}", id);
                throw;
            }
        }

        public async Task<bool> DeleteAsync(long id)
        {
            try
            {
                // First delete all related details
                await _detailRepository.DeleteByMasterIdAsync(id);
                
                // Then delete the master
                return await _repository.DeleteAsync(id);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting refund task master: {Id}", id);
                throw;
            }
        }

        public async Task<RefundTaskMasterResponse?> GetWithDetailsAsync(long id)
        {
            return await GetByIdAsync(id);
        }

        public async Task<(long masterId, int actualCount)> CreateWithHisDataAsync(RefundTaskMasterCreateRequest request, int? maxCount = null)
        {
            using var connection = _repository.GetConnection(); // 获取数据库连接
            connection.Open();
            using var transaction = connection.BeginTransaction();
            
            try
            {
                _logger.LogInformation("开始创建退费任务主记录及明细数据，使用事务保护");
                
                // 1. 创建主表记录
                var master = new RefundTaskMaster
                {
                    Username = request.Username,
                    Fullname = request.Fullname,
                    AccountCount = 0, // 初始值，后续会更新
                    AccountSumBalance = 0 // 初始值，后续会更新
                };

                var masterId = await _repository.CreateAsync(master, connection, transaction);
                _logger.LogInformation("事务中创建退费任务主记录成功，ID: {MasterId}", masterId);

                // 2. 从HIS数据库查询明细数据（使用HIS数据库连接）
                var hisRefundData = await _detailRepository.GetHisRefundDataAsync(maxCount);
                var hisDataCount = hisRefundData.Count();
                
                _logger.LogInformation("从HIS数据库获取到 {Count} 条退费数据", hisDataCount);

                if (hisDataCount > 0)
                {
                    // 3. 设置master_id并批量插入明细数据
                    var details = hisRefundData.Select(data => new RefundTaskDetail
                    {
                        MasterId = masterId,
                        PatientId = data.PatientId,
                        AccountId = data.AccountId,
                        AccountIndex = data.AccountIndex,
                        Balance = data.Balance,
                        ContactCount = 0,
                        PhoneNumber = data.PhoneNumber,
                        PatName = data.PatName,
                        IdNumber = data.IdNumber,
                        Sex = data.Sex,
                        NextOfKin = data.NextOfKin,
                        NextOfKinPhone = data.NextOfKinPhone,
                        GuardianName = data.GuardianName,
                        GuardianIdcode = data.GuardianIdcode
                    }).ToList();

                    var batchInsertSuccess = await _detailRepository.BatchCreateAsync(details, connection, transaction);
                    if (!batchInsertSuccess)
                    {
                        _logger.LogError("事务中批量插入退费任务明细失败，主记录ID: {MasterId}", masterId);
                        throw new Exception("批量插入退费任务明细失败");
                    }

                    _logger.LogInformation("事务中成功批量插入 {Count} 条退费任务明细", details.Count);

                    // 4. 更新主表的汇总数据
                    var updateSuccess = await _repository.UpdateBalanceFromDetailsAsync(masterId, connection, transaction);
                    if (!updateSuccess)
                    {
                        _logger.LogError("事务中更新主表汇总数据失败，主记录ID: {MasterId}", masterId);
                        throw new Exception("更新主表汇总数据失败");
                    }

                    _logger.LogInformation("事务中成功更新主表汇总数据，主记录ID: {MasterId}", masterId);
                    
                    // 提交事务
                    transaction.Commit();
                    _logger.LogInformation("事务提交成功，退费任务创建完成，主记录ID: {MasterId}, 明细数量: {DetailCount}", masterId, details.Count);
                    
                    return (masterId, details.Count);
                }
                else
                {
                    _logger.LogWarning("从HIS数据库未获取到退费数据，仅创建空主记录，主记录ID: {MasterId}", masterId);
                    
                    // 即使没有明细数据也提交事务
                    transaction.Commit();
                    return (masterId, 0);
                }
            }
            catch (Exception ex)
            {
                // 发生异常时回滚事务
                transaction.Rollback();
                _logger.LogError(ex, "创建退费任务事务失败，已回滚所有操作");
                throw new InvalidOperationException("创建退费任务失败，所有操作已回滚", ex);
            }
        }
    }
}
